<template>
  断点续传
  <el-upload
  class="upload-demo"
  drag
  action
  :auto-upload="false"
  :show-file-list="false"
  :on-change="changeFile"
  enctype="multipart/form-data" 
  multiple>
  <i class="el-icon-upload"></i>
  <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
  <div class="el-upload__tip" slot="tip">只能上传jpg/png文件，且不超过500kb</div>
</el-upload>
  <div class="progress">
    <span>上传进度：{{totalText}}%</span>
    <el-button type="success" v-if="total>0 && total<100" @click="handleBtn">{{btnText}}</el-button>
  </div>
  <div class="uploadImg" v-if="video">
    <video :src="video" controls/>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
import axios from 'axios'
import SparkMD5 from 'spark-md5'
import {fileParse} from '../utils/index'
/* 
6、文件断点续传
  文件上传有两套方案
    1、基于文件流(form-data)   // element-ui上传组件默认是基于文件流端
    2、客户端需要把文件化为base64

  默认上传
    格式：multipart/form-data
    数据格式：form-data
    file 文件流信息
    filename 文件名
  
  上传成功后获取服务器返回信息，通知on-success回调函数执行
*/

export default defineComponent({
  name: 'Upload3',
  setup() {
    const count = ref(0)
    return { count }
  },
  data() {
    return {
      img: null,
      total: 0,
      video: null,
      btn: false,
      abort: false,
      hash: null,
      partList: []
    }
  },
  computed: {
   btnText() {
      return this.btn ? '继续' : '暂停'
    },
    totalText() {
      return this.total > 100 ? 100 : this.total
    }
  },
  methods: {
  async changeFile(file) {
      if(!file) return
      file = file.raw
      console.log(file)

      // 格式校验
      /* 
        把上传的文件先进行解析（FileReader）
        把其转换base64编码格式
        自己基于axios把信息传递给服务器
      */
     // 解析为buffer数据
     // 我们会把文件切片处理，把一个文件分割成为好几个部分（固定数量或固定大小）
     // 每个切片有自己的部分数据和自己的名字
     // HASH-1.mp4
     // HASH-2.mp4
     // ... 
     let buffer = await fileParse(file, 'buffer'),
         spark = new SparkMD5.ArrayBuffer(),
         hash,
         suffix;
      spark.append(buffer)
      hash = spark.end()
      suffix = /\.([0-9a-zA-Z]+)$/i.exec(file.name)[1] // 获取后缀名

      // 创建100个切片
      let partList = [],
          partsize = file.size / 100, // 将文件分成100份： 得每份等大小值
          cur = 0 
      for(let i=0; i<100; i++) {
        let item = {
          // file.slice(cur,cur+partsize) 切取文件件部分信息
          chunk: file.slice(cur,cur+partsize),
          filename: `${hash}_${i}.${suffix}`
        }
        cur += partsize
        // 将切片存储在集合中
        partList.push(item)
      }

      this.partList = partList
      this.hash = hash
      this.sendRequest()
    },
    async sendRequest() {
      // 根据100个切片创建100个请求（集合）
      let requestList = []
      this.partList.forEach((item,i) => {
        let fn = () => {
          // 创建一个formData
          let formData = new FormData()
          formData.append('chunk', item.chunk)
          formData.append('filename', item.filename)
          return axios.post('/api/single3', formData, {
            headers: {
              'Content-Type': 'multipart/form-data'
            }
          }).then(res => {
            res = res.data
            if(res.code == 0) {
              // 上传文件进度
              this.total += 1
              console.log(this.total)
              // 传完的切片我们把它移除掉
              this.partList.splice(i, 1)
            }
          })
        }
        requestList.push(fn)
      })
      // 传递方式：并行（ajax.abort）或串行（基于标志控制不发送）
      let i = 0
      let complete = async () => {
        let result = await axios.get('/api/merge',{
          params: {
            hash: this.hash
          }
        })
        result = result.data
        if(result.code == 0) {
          this.video =  result.path
        }
      }
      let send = async () => {
        // 已经中断则不再上传
        if(this.abort) return
        if(i>=requestList.length){
          // 都传完了
          complete()
          return
        }
        await requestList[i]()
        i++
        send()
      }
      send()
    },
    handleBtn() {
      if(this.btn) {
        // 断点续传
        this.btn = false
        this.abort = false
        this.sendRequest()
        return
      }
      // 暂停上传
      this.btn = true
      this.abort = true
    }
  }
})
</script>
